package edu.calvin.djs32.cs214.interpreters.prettyprinter;

import static org.easymock.EasyMock.expect;
import static org.junit.Assert.assertSame;

import org.junit.Before;
import org.junit.Test;

import edu.calvin.cs214.hobbes2008.ApplicationTIR;
import edu.calvin.cs214.hobbes2008.HobbesTIR;
import edu.calvin.cs214.hobbes2008.IdentifierTIR;
import edu.calvin.cs214.hobbes2008.IfTIR;
import edu.calvin.cs214.hobbes2008.IntegerTIR;
import edu.calvin.cs214.hobbes2008.LetTIR;
import edu.calvin.cs214.hobbes2008.StringTIR;
import edu.calvin.cs214.hobbes2008.TupleTIR;
import edu.calvin.djs32.cs214.interpreters.support.EasyMockControl;

public class PrettyPrinterTest {
	private PrettyPrinter myPrettyPrinter;
	private EasyMockControl myControl;
	private IHTMLGenerator myGenerator;
	
	@Before
	public void setUp() {
		
		myControl = new EasyMockControl();
		myGenerator = myControl.createMock(IHTMLGenerator.class);
		myPrettyPrinter = new PrettyPrinter(myGenerator);
	}
	
	@Test
	public void shouldPrettyPrintIntegers() {
		IntegerTIR tir = new IntegerTIR(123);
		 
		expect(myGenerator.span("123", "integer")).andReturn("456");

		myControl.replay();
		assertSame("456", myPrettyPrinter.visitInteger(tir));

		myControl.verify();
	}
	
	@Test
	public void shouldPrettyPrintStrings() {
		StringTIR tir = new StringTIR("foo");
		 
		expect(myGenerator.span("&lsquo;foo&rsquo;", "string")).andReturn("bar");

		myControl.replay();
		assertSame("bar", myPrettyPrinter.visitString(tir));

		myControl.verify();
	}

	@Test
	public void shouldPrettyPrintEmptyTuple() {
		TupleTIR tir = new TupleTIR();
		 
		expect(myGenerator.span("()", "tuple")).andReturn("bar");

		myControl.replay();
		assertSame("bar", myPrettyPrinter.visitTuple(tir));

		myControl.verify();
	}
	
	@Test
	public void shouldPrettyPrintInterestingTuples(){
		IntegerTIR tir1 = new IntegerTIR(123);
		IntegerTIR tir2 = new IntegerTIR(456);
		StringTIR tir3 = new StringTIR("foo");
		TupleTIR tir = new TupleTIR(tir1, tir2, tir3);

		expect(myGenerator.span("123", "integer")).andReturn("bar1");
		expect(myGenerator.span("456", "integer")).andReturn("bar2");
		expect(myGenerator.span("&lsquo;foo&rsquo;", "string")).andReturn("bar3");
		expect(myGenerator.span("(bar1, bar2, bar3)", "tuple")).andReturn("bar");

		myControl.replay();
		assertSame("bar", myPrettyPrinter.visitTuple(tir));

		myControl.verify();		
	}
	
	@Test
	public void shouldPrettyPrintApplication(){
		IdentifierTIR iTir = new IdentifierTIR("+");
		IntegerTIR tir1 = new IntegerTIR(123);
		IntegerTIR tir2 = new IntegerTIR(456);
		TupleTIR tTir = new TupleTIR(tir1, tir2);
		ApplicationTIR tir = new ApplicationTIR(iTir, tTir);
		 
		expect(myGenerator.span("+", "identifier")).andReturn("id");
		expect(myGenerator.span("123", "integer")).andReturn("bar2");
		expect(myGenerator.span("456", "integer")).andReturn("bar3");
		expect(myGenerator.span("(bar2, bar3)", "tuple")).andReturn("tuple");
		expect(myGenerator.span("idtuple", "application")).andReturn("app");

		myControl.replay();
		assertSame("app", myPrettyPrinter.visitApplication(tir));

		myControl.verify();
	}
	
	@Test
	public void shouldPrettyPrintIf(){
		IntegerTIR tir1 = new IntegerTIR(1);
		IntegerTIR tir2 = new IntegerTIR(2);
		IntegerTIR tir3 = new IntegerTIR(3);
		IfTIR ife = new IfTIR(tir1, tir2, tir3);
		
		expect(myGenerator.span("1", "integer")).andReturn("int1");
		expect(myGenerator.span("2", "integer")).andReturn("int2");
		expect(myGenerator.span("3", "integer")).andReturn("int3");
		expect(myGenerator.span("if int1 then int2 else int3 end", "if")).andReturn("ife");
		
		myControl.replay();
		
		assertSame("ife", myPrettyPrinter.visitIf(ife));

		myControl.verify();
		
	}
	
	 @Test
     public void shouldInterpret(){
		 HobbesTIR tir = myControl.createMock(HobbesTIR.class);
		 
		 expect(tir.accept(myPrettyPrinter)).andReturn("joebob");
		 expect(myGenerator.pre("joebob")).andReturn("foobar");

		 myControl.replay();
		 assertSame("foobar", myPrettyPrinter.interpret(tir));

		 myControl.verify();
     }
	 
	 @Test
	 public void shouldPrettyPrintLet() {
		IdentifierTIR tir1 = new IdentifierTIR("+");
		IntegerTIR tir2 = new IntegerTIR(2);
		IntegerTIR tir3 = new IntegerTIR(3);
		LetTIR let = new LetTIR(tir1, tir2, tir3);
		
		expect(myGenerator.span("+", "identifier")).andReturn("ident");
		expect(myGenerator.span("2", "integer")).andReturn("int2");
		expect(myGenerator.span("3", "integer")).andReturn("int3");
		expect(myGenerator.span("let ident := int2 in int3", "let")).andReturn("let");
		
		myControl.replay();
		
		assertSame("let", myPrettyPrinter.visitLet(let));

		myControl.verify();
		 
	 }


}
